#version 410

out vec4 FragColor;

struct SpotLight
{
	float ambientIntensity;
	float diffuseIntensity;
	float specularIntensity;
	float specularPower;
	vec3 color;
	vec3 position;
	float attConstant;
	float attLinear;
	float attExp;
	vec3 direction;
	float cutoff;
};

uniform SpotLight light;
uniform sampler2D shadowMap;
uniform sampler2D worldPosMap;
uniform sampler2D diffuseMap;
uniform sampler2D normalMap;

uniform vec2 screenSize;
uniform vec3 eyeWorldPos;
uniform mat4 projLightMat;

float getShadowFactor(vec4 worldPos)
{
	vec4 lightPos = projLightMat * worldPos;
	vec3 coords = lightPos.xyz / lightPos.w;
	vec2 uvCoords;
    uvCoords.x = 0.5 * coords.x + 0.5;
    uvCoords.y = 0.5 * coords.y + 0.5;
    float z = 0.5 * coords.z + 0.5;
    float depth = texture(shadowMap, uvCoords).x;

    if (depth < z - .0001)
        return 0.5;
    else
        return 1.0;
}

vec2 getTexCoord()
{
   return gl_FragCoord.xy / screenSize;
}

vec4 getLightInfluence(vec4 lWorldPos, vec3 norm)
{
	vec3 worldPos = lWorldPos.xyz;
	vec3 lightToPixel = normalize(worldPos - light.position);
	float spotFactor = dot(lightToPixel, light.direction);
	float shadowFactor = getShadowFactor(lWorldPos);

	if (spotFactor > light.cutoff)
	{
		vec3 lightDirection = worldPos - light.position;
		float distance = length(lightDirection);
		lightDirection = normalize(lightDirection);

		vec4 ambientColor = vec4(light.color, 1.0f) * light.ambientIntensity;
		float diffuseFactor = dot(norm, -lightDirection);

		vec4 diffuseColor  = vec4(0, 0, 0, 0);
		vec4 specularColor = vec4(0, 0, 0, 0);

		if (diffuseFactor > 0) 
		{
			diffuseColor = vec4(light.color, 1.0f) * light.diffuseIntensity * diffuseFactor;
			vec3 vertexToEye = normalize(eyeWorldPos - worldPos);
			vec3 lightReflect = normalize(reflect(lightDirection, norm));
			float specularFactor = dot(vertexToEye, lightReflect);
			specularFactor = pow(specularFactor, light.specularPower);
			if (specularFactor > 0)
			{
				specularColor = vec4(light.color, 1.0f) * light.specularIntensity * specularFactor;
			}
		}

		vec4 color = (ambientColor + shadowFactor*(diffuseColor + specularColor));

		// Spot light attenuation formula
		float attenuation =  light.attConstant + light.attLinear * distance + light.attExp * distance * distance;

		color = color / attenuation;

		return color * (1.0 - (1.0 - spotFactor) * 1.0/(1.0 - light.cutoff));
	}
	else
	{
		return vec4(0,0,0,0);
	}
}

void main()
{
	vec2 texCoord = getTexCoord();
    vec4 worldPos = texture(worldPosMap, texCoord);
    vec4 color = texture(diffuseMap, texCoord);
    vec4 normal = texture(normalMap, texCoord);
	FragColor = vec4(color.rgb, 1.0) * getLightInfluence(worldPos, normal.xyz);
}